home *** CD-ROM | disk | FTP | other *** search
- /*
- * The original copyright owners of the accompanying source code files have
- * agreed to place such code into the public domain. Accordingly, anyone
- * who receives or obtains a copy of such source code is freely entitled to
- * reproduce, use and otherwise exploit such code (including the right to
- * make derivative works), at his/her own risk and expense, without any
- * obligation or liability to the original copyright owners.
- *
- * We would appreciate (but do not require) that the following message be
- * included in any derivative works:
- *
- * "Portions of this program were developed by Peter Broadwell, Rob Myers
- * and Robin Schaufler while working in Silicon Valley."
- *
- * The accompanying source code files and related documentation materials
- * are distributed on an "AS IS" basis, without any warranties or
- * guarantees of any kind. All implied warranties, including the implied
- * warranties of merchantability and of fitness for any particular purpose,
- * are expressly disclaimed.
- */
- #include "gl.h"
- #include "geom.h"
- #include "class.h"
- #include "selectors.h"
- #include "classIds.h"
- #include "mbox.h"
- #include "individual.h"
- #include "behavior.h"
- #include "colors.h"
- #include "pick.h"
- #include "doers.h"
- #include "panel.h"
- #include "valuator.h"
- #include "objIds.h"
-
- #define PI 3.14159265358979323844
- #define DEG(x) ((float)x*(float)180/PI)
- #define RAD(x) ((float)x*PI/(float)180)
-
- extern behavior advancerTemplate;
- extern behavior expanderTemplate;
- extern behavior surfDieTemplate;
- extern char frozen;
- extern char dobackground;
- extern subscr *findvars();
- model *replicateMsegs();
- extern model selectModel;
- extern masterPanel *thePanel;
- extern int unsophistication;
- extern int controls;
- extern individual *us;
- extern long fishPop;
- extern int dumper;
-
- /*
- * current selection
- */
- individual *curIndiv = NULL;
- int inNothing = TRUE;
-
-
- /*
- * instantiate and initialize an individual's model list
- */
- individual *
- replicateModel(self)
- register individual *self;
- {
- /* reproduce list of model segments */
- self->descr = replicateMsegs(self->descr);
- }
-
- /*
- * instantiate and initialize a model tree, beginning with firstModel
- */
- model *
- replicateMsegs(firstModel)
- register model *firstModel;
- {
- register model *m, *newm, *lastm;
-
- for (m = firstModel, lastm = NULL; m; m = m->next, lastm = newm) {
- newm = (model *)gfmalloc(sizeof(model));
- #ifdef MALDEBUG
- if(*(char *)newm) {
- printf("replicatingMsegs: onto non empty gfmalloc 0x%x\n",newm);
- }
- #endif /* MALDEBUG */
- bcopy(m, newm, sizeof(model));
- newm->compiled = FALSE;
- initcolor(newm);
- newm->kids = replicateMsegs(newm->kids);
- if (lastm)
- lastm->next = newm;
- else firstModel = newm;
- }
- return firstModel;
- }
-
- /*
- * initialize the color slot choice for a model segment
- */
- initcolor(m)
- register model *m;
- {
- rgbcolor hue;
-
- if(m->color >= BACK_GROUND_BASE) return;
- gmcolor(m->color, &hue.r, &hue.g, &hue.b);
- m->color = getMapIndex();
- mapcaller(m->color, hue.r, hue.g, hue.b);
- }
-
- /*
- * service each individual's tic, by servicing each of its subscribedTos
- */
- /* ARGSUSED */
- individual *
- serviceTic(self, argtype, rootObject)
- register individual *self;
- long argtype;
- mailbox *rootObject;
- {
- register subscr *sentry;
- register subscr *tmp_next;
-
- pushmatrix();
- if (!frozen) {
- for (sentry=self->them.subscribedTo; sentry; sentry = tmp_next) {
- self->curVars = sentry;
- tmp_next = sentry->next;
- if(Msg(sentry->member, DOIT, INSTARG, self) == 0) {
- popmatrix();
- return NULL;
- }
- }
- }
- Msg(self, DRAW, NOARG, NULL);
- popmatrix();
- return self;
- }
-
-
- moveUp(self)
- register individual *self;
- {
- double hyp, atan2(), sqrt();
-
- if (!frozen) {
- /* rotate individual to (position-lastPosition) */
- self->delta.x = self->position.x - self->lastPosition.x;
- self->delta.y = self->position.y - self->lastPosition.y;
- self->delta.z = self->position.z - self->lastPosition.z;
-
- /* the following makes the fish follow her nose */
- hyp = sqrt(fabs((float)(self->delta.x * self->delta.x +
- self->delta.y * self->delta.y)));
-
- if (hyp == 0.0) {
- self->rotation.y =
- ((self->delta.z > 0) ? self->delta.z : -self->delta.z) * 90 * 10;
- self->rotation.z = 0;
- }
- else {
- self->rotation.y = 10 * DEG(atan2(hyp, (float)self->delta.z));
- self->rotation.z = 10 * DEG(atan2((float)self->delta.y,
- (float)self->delta.x));
- }
- self->rotation.x = 0;
-
- /*
- printf("self->delta is %d %d %d \t", self->delta.x,
- self->delta.y,
- self->delta.z);
- printf("rot is %d %d %d \n",self->rotation.x,
- self->rotation.y,
- self->rotation.z); /* */
-
- self->lastPosition = self->position;
- }
- }
-
-
- /*
- * draw an individual with each model segment
- */
- drawIndividual(self)
- register individual *self;
- {
- register model *aModel;
- register subscr *entry; /* only looked at when debugging */
-
- Msg(self, MOVE, 0, NULL);
- aModel = self->descr;
- if((aModel && aModel->color < BACK_GROUND_BASE) || dobackground) {
- if (entry = findvars(self, VOXEL))
- newVoxPosition(entry->member, &self->position, self);
-
- /*
- * transform entire individual to its new orientation
- */
- translate((float)self->position.x,
- (float)self->position.y,
- (float)self->position.z);
-
- scale(self->scale, self->scale, self->scale);
-
- rotate(self->rotation.z , 'z');
- rotate(self->rotation.y , 'y');
- /* rotate(self->rotation.x , 'x'); /* not needed yet */
-
- /*
- * counteract effect of rotating the fishbowl
- */
- rotate(-900, 'y');
-
- dolater(self);
- }
- }
-
- /*
- * draw each model segment
- */
- drawModels(self,unit)
- individual *self;
- float unit[8];
- {
- long oct;
- float z,w;
-
- w = unit[7];
- if(w != 0.0) {
- z = unit[6]/w;
- }
- else {
- z = unit[6];
- }
-
- if(unit[2]<z)
- oct = 4;
- else
- oct = 0;
-
- if(self->them.me.myClass->classId == 0) burp("drawModels",self);
- if(self->flags & ORDER) {
- if(oct>=4) { /* fish going away from us, so draw body then tail */
- drawModel(self->descr,self,0);
- drawModel(self->descr->next,self,0);
- }
- else {
- drawModel(self->descr->next,self,0);
- drawModel(self->descr,self,0);
- }
- }
- else {
- drawModel(self->descr,self,1);
- }
- if(self->flags & PICKED) {
- drawModel(&selectModel, self,0);
- }
- }
-
- /*
- * transform each model segment, to set up its actual drawing
- */
- drawModel(firstModel, indiv, chain)
- register model *firstModel;
- register individual *indiv;
- register int chain;
- {
- register model *aModel;
-
- for (aModel = firstModel; aModel ; aModel = chain ? aModel->next : NULL) {
- if(aModel->kids == aModel->next && aModel->kids != NULL) burp("drawModel",indiv);
- if(aModel == NULL) continue;
- pushmatrix();
- rotate(aModel->rotation.z , 'z');
- /* rotate(aModel->rotation.y , 'y'); /* not needed yet */
- /* rotate(aModel->rotation.x , 'x'); /* not needed yet */
- translate((float)aModel->translate.x,
- (float)aModel->translate.y,
- (float)aModel->translate.z);
- scale(aModel->scale.x, aModel->scale.y, aModel->scale.z);
-
- /* don't draw model segments which are too declasse for the user */
- if (aModel->declasse <= unsophistication)
- drawobj(aModel, indiv);
-
- /* after drawing this model segment, draw its kids' models */
- drawModel(aModel->kids, indiv, 1);
-
-
- popmatrix();
- }
- }
-
- /*
- * draw a model segment, compiling it if necessary
- */
- drawobj(m, indiv)
- register model *m;
- individual *indiv;
- {
- register long *v;
- register point *pnts = m->points;
- register point *p, *p1;
- Object oldobj;
-
- if(!m->compiled) {
- oldobj = getopenobj();
- m->component = (Object)m;
- makeobj(m->component);
- pushLongName(indiv);
- pushmatrix();
- /* draw the polygonal areas */
- if (m->color < BACK_GROUND_BASE)
- fishWritemask(FOREGROUND);
- else fishWritemask(BACKGROUND);
- fishColor(m->color);
- if(m->texture)
- setpattern(m->texture);
- v = m->vertices;
- while(*v) {
- p = &pnts[*(v++)];
- pmvi(p->x, p->y, p->z);
- while(*v) {
- p = &pnts[*(v++)];
- pdri(p->x, p->y, p->z);
- }
- pclos();
- v++;
- }
- /* outline the polygons */
- if (m->outlined) {
- fishColor(EDGE_COLOR);
- v = m->vertices;
- while(*v) {
- p1 = p = &pnts[*(v++)];
- movei(p->x, p->y, p->z);
- while(*v) {
- p = &pnts[*(v++)];
- drawi(p->x, p->y, p->z);
- }
- drawi(p1->x, p1->y, p1->z);
- /* v++; /* VISUAL HACK; only draw 1st poly's edge */
- }
- }
- popmatrix();
- popLongName();
- closeobj();
- if (oldobj != -1)
- editobj(oldobj);
- m->compiled = TRUE;
- }
- callobj(m->component);
- }
-
- /*
- * check each model segment in the individual, to see if a bad
- * model color index has been assigned to it
- */
- badModelIndex(firstModel, indiv)
- register model *firstModel;
- register individual *indiv;
- {
- register model *aModel;
- register int r = FALSE;
-
- for (aModel = firstModel; aModel ; aModel = aModel->next) {
-
- if (aModel->color == MODEL_COLOR_BASE)
- return TRUE;
-
- /* after checking this model segment, check its kids' models */
- if (r = badModelIndex(aModel->kids, indiv))
- return r;
- }
- return r;
- }
-
- /*
- * gffree up an individual and all of his alloc'd mems
- */
- freeIndividual(self)
- register individual *self;
- {
- register subscr *s;
-
- /***************
- dumpSubscribers("self's subscribers", self->them.subscribers);
- ***************/
- if(isSuper(self,GUPPY))
- fishPop--;
- while (s = self->them.subscribers)
- unsubscribe(self, s->member);
-
- /***************
- dumpSubscribers("self's subscribedTos", self->them.subscribedTo);
- ***************/
- while (s = self->them.subscribedTo)
- unsubscribe(s->member, self);
-
- if (self == curIndiv)
- curIndiv = NULL;
-
- freeMsegs(self->descr);
- dontdo(self);
- gffree(self);
- }
-
- /*
- * gffree a model tree, beginning with firstModel
- */
- freeMsegs(firstModel)
- register model *firstModel;
- {
- register model *m, *nextm;
-
- for (m = firstModel; m; m = nextm) {
- nextm = m->next;
- delobj(m->component);
- freeMapIndex(m->color);
- freeMsegs(m->kids);
- gffree(m);
- }
- }
-
- /*
- * begin picking on an individual (button goes down on it)
- */
- bselIndividual(self, argtype, hit)
- register individual *self;
- long argtype;
- hitstruct *hit;
- {
- /* printf("bselIndividual: BEGIN SELECT on 0x%x, class %d\n",
- self, ((inst *)self)->myClass->classId); /* */
-
- Msg(self, SELECT, argtype, hit);
- }
-
- /*
- * begin picking on a new individual (button wanders into it while down)
- */
- nselIndividual(self, argtype, hit)
- register individual *self;
- long argtype;
- hitstruct *hit;
- {
- /* printf("nselIndividual: NEW SELECT on 0x%x, class %d\n",
- self, ((inst *)self)->myClass->classId); /* */
-
- Msg(self, SELECT, argtype, hit);
- }
-
-
- /*
- * continue picking on an individual (button remains down on it)
- */
- /* ARGSUSED */
- cselIndividual(self, argtype, hit)
- register individual *self;
- long argtype;
- hitstruct *hit;
- {
- /* printf("cselIndividual: CONTINUE SELECT on 0x%x, class %d\n",
- self, ((inst *)self)->myClass->classId); /* */
- }
-
- /*
- * end picking on an individual (button goes up on it)
- */
- /* ARGSUSED */
- eselIndividual(self, argtype, hit)
- register individual *self;
- long argtype;
- hitstruct *hit;
- {
- /* printf("eselIndividual: END SELECT on 0x%x, class %d\n",
- self, ((inst *)self)->myClass->classId); /* */
- }
-
- /*
- * no longer picking on an individual (button leaves it while down)
- */
- /* ARGSUSED */
- oselIndividual(self, argtype, hit)
- register individual *self;
- long argtype;
- hitstruct *hit;
- {
- /* printf("oselIndividual: OLD SELECT on 0x%x, class %d\n",
- self, ((inst *)self)->myClass->classId); /* */
- }
-
- /*
- * begin picking on nothing (button goes down on it)
- */
- /* ARGSUSED */
- bselNone(self, argtype, hit)
- register individual *self;
- long argtype;
- hitstruct *hit;
- {
- /* printf("bselNone: BEGIN SELECT on NOTHING\n"); /* */
-
- inNothing = TRUE;
- }
-
- /*
- * end picking on nothing (button goes up on it)
- */
- /* ARGSUSED */
- eselNone(self, argtype, hit)
- register individual *self;
- long argtype;
- hitstruct *hit;
- {
- /* printf("eselNone: END SELECT on NOTHING\n"); /* */
-
- if (inNothing) {
- /***********
- if (curIndiv) {
- Msg(curIndiv, DESELECT, NOARG, NULL);
- }
- **********/
- controls = !controls;
- }
- }
-
- /* ARGSUSED */
- selectIndiv(self, argtype, hit)
- register individual *self;
- long argtype;
- hitstruct *hit;
- {
- inNothing = FALSE;
-
- if (self != curIndiv) {
- if (curIndiv)
- Msg(curIndiv, DESELECT, NOARG, NULL);
- self->flags |= PICKED;
- curIndiv = self;
- controls = TRUE;
- emptyPanel(thePanel);
- Msg(thePanel, INIT, NOARG, NULL);
-
- Msg(self, ADDPANEL, NOARG, NULL);
- }
- }
-
- deselectIndiv(self)
- register individual *self;
- {
- if (self) {
- self->flags &= ~PICKED;
- if (self != curIndiv)
- return;
- removePanel(self);
- }
- curIndiv = NULL;
- }
-
- /* ARGSUSED */
- addBehavior(self, argtype, doer)
- register individual *self;
- int argtype;
- behavior *doer;
- {
- panel *aPanel;
-
- if (! (aPanel = (panel *)self->controls)) {
- printf("addBehavior: current individual has no panel.\n");
- return;
- }
- subscribe(doer, self);
- self->curVars = self->them.subscribedTo;
- /* printf("addBehavior: calling addpanel for behavior %d\n",
- doer->them.me.myClass->classId); /* */
- Msg(doer, ADDPANEL, INTARG, self);
- }
-
- postIndividual(self, argtype, doer)
- register individual *self;
- int argtype;
- behavior *doer;
- {
- subscr *sentry;
-
- /*
- * if already subscribed to posted behavior,
- * highlight it in the panel.
- */
- if (sentry = findvars(self, doer->them.me.myClass->classId)) {
- /* printf("postIndividual: already have %d behavior\n",
- doer->them.me.myClass->classId); /* */
-
- /*
- * else subscribe to it and add it to the panel.
- */
- } else {
- addBehavior(self, argtype, doer);
- }
- }
-
- /* ARGSUSED */
- dieIndividual(self, argtype, arg)
- register individual *self;
- long argtype;
- char *arg;
- {
- expire(self, 40.0);
- }
-
- /*
- * snuff a fish, complete with burp
- */
- expire(self, bubblesize)
- register individual *self;
- float bubblesize;
- {
- expanderVars *bubVars;
- individual *burp, *makeBub();
-
- burp = makeBub();
- subscribe(us, burp);
-
- subscribe(&advancerTemplate, burp);
- subscribe(&expanderTemplate, burp);
- subscribe(&surfDieTemplate, burp);
- Msg(burp, INIT, NOARG, NULL);
-
- if (bubVars = (expanderVars *)findvars(burp, EXPANDER)) {
- bubVars->scaleMax = bubblesize;
- }
- burp->position.x = self->position.x;
- burp->position.y = self->position.y;
- burp->position.z = self->position.z;
-
- burp->lastPosition.x = burp->position.x - burp->velocity.x;
- burp->lastPosition.y = burp->position.y - burp->velocity.y;
- burp->lastPosition.z = burp->position.z - burp->velocity.z;
-
- Msg (self, DESELECT, 0, NULL);
- Msg (self, FREE, 0, NULL);
- }
-
- /*
- * construct an individual's control panel
- */
- addPanel(self)
- register individual *self;
- {
- register masterPanel *aPanel = thePanel;
- register subscr *sentry;
-
- addIndivPanel(self, sizeof(masterPanel), aPanel);
- /* append controls for each behavior the individual is subscribed to */
- for (sentry = self->them.subscribedTo; sentry; sentry = sentry->next) {
- self->curVars = sentry;
- Msg(sentry->member, ADDPANEL, INTARG, self);
- }
- }
-
-
- #define SPEEDER
- #ifdef SPEEDER
- /*
- * initialize the individual's subtree of panels
- */
- /* ARGSUSED */
- addIndivPanel(self, argtype, dad)
- register individual *self;
- long argtype;
- register panel *dad;
- {
- panel *p;
- int flags;
- rectangle r, rw;
- rectanglef rwf;
- point2d inset, button;
- extern panel *makeValuator(), *makeValuatorf();
- extern panel *makeValDelta(), *makePanel(), *makeMenu();
- extern panel *makeValMesg(), *makeValMesgf();
-
- /* individual's floor panel */
- setrect(&r, 0,((masterPanel *)dad)->highwater.y, 255,155);
- ((masterPanel *)dad)->highwater.y += 155;
- buildIndFloor(&r, INDIVFLOOR);
- p = dad->kids = makePanel(dad->kids, dad, &r, INDIVFLOOR);
-
- self->controls = (char *)p;
-
- /* individual's size control */
- flags = NULL;
- setrect(&r, 10,10, 52,100);
- setpt2d(&inset, 0,6);
- setrect(&rwf, 0.0,8.0, 0.0,-7.8);
- buildIndSize(&r, ((inst *)self)->myClass->classId, INDSIZE, INDSIZET);
- p->kids = makeValuatorf(p->kids, p, flags, &r, &inset, &rwf,
- NULL, &self->scale, INDSIZE, INDSIZET);
-
- /* NOTE: this valuator is out of paint order at its origin, */
- /* to avoid overlap from the heading control */
-
- /* death to fish control */
- flags = NULL;
- setrect(&r, 105,85, 55,25);
- setpt2d(&button, 1, 1);
- buildIndSnuff(&r, ((inst *)self)->myClass->classId, INDSNUFF,INDSNUFFT);
- p->kids = makeMenu(p->kids, p, flags, &r, &button,
- self, DIE, INDSNUFF, INDSNUFFT);
-
- /* individual's speed control */
- flags = NULL;
- setrect(&r, 10,120, 240,25);
- setpt2d(&inset, 15,0);
- setrect(&rwf, 200.0,0.0, -190.0,0.0); /* speed from 10 to 200 */
- buildIndSpeed(&r, ((inst *)self)->myClass->classId, INDSPEED,INDSPEEDT);
- p->kids = makeValuatorf(p->kids, p, flags, &r, &inset, &rwf,
- &self->speed, NULL, INDSPEED, INDSPEEDT);
-
- /* individual's heading control */
- flags = NULL;
- setrect(&r, 72,10, 120,70);
- setpt2d(&inset, 0,0);
- setrect(&rwf, -0.2,0.0, 0.4,0.0);
- buildIndHeading(&r, ((inst *)self)->myClass->classId, INDHEAD,INDHEADT);
- p->kids = makeValMesgf(p->kids, p, flags, &r, &inset, &rwf, 0.0, 0.0,
- self, NEWHEADING, AUTORESET, INDHEAD, INDHEADT);
-
- /* individual's azimuth control */
- flags = NULL;
- setrect(&r, 202,10, 48,100);
- setpt2d(&inset, 0,15);
- setrect(&rw, 0,20, 0,-40);
- buildIndAzimuth(&r, ((inst *)self)->myClass->classId, INDAZ, INDAZT);
- p->kids = makeValMesg(p->kids, p, flags, &r, &inset, &rw, 0, 0,
- self, NEWAZIMUTH, NOAUTORESET, INDAZ, INDAZT);
-
- /* test menu buttons */
- /*
- flags = NULL;
- setrect(&r, 10, 160, 200, 200);
- setpt2d(&button, 4, 3);
- buildMenu1(&r, &button, MENU1, MENUH1);
- p->kids = makeMenu(p->kids, p, flags, &r, &button,
- self, TESTMENU, MENU1, MENUH1);
- /* */
- }
-
- #else /* SPEEDER */
- /*
- * initialize the individual's subtree of panels
- */
- addIndivPanel(self, argtype, dad)
- register individual *self;
- long argtype;
- register panel *dad;
- {
- panel *p;
- int flags;
- rectangle r, rw;
- rectanglef rwf;
- point2d inset, button;
- extern panel *makeValuator(), *makeValuatorf();
- extern panel *makeValDelta(), *makePanel(), *makeMenu();
- extern panel *makeValMesg(), *makeValMesgf();
-
- /* individual's floor panel */
- setrect(&r, 0,((masterPanel *)dad)->highwater.y, 255,120);
- ((masterPanel *)dad)->highwater.y += 120;
- buildIndFloor(&r, INDIVFLOOR);
- p = dad->kids = makePanel(dad->kids, dad, &r, INDIVFLOOR);
-
- self->controls = (char *)p;
-
- /* individual's size control */
- flags = NULL;
- setrect(&r, 10,10, 52,100);
- setpt2d(&inset, 0,6);
- setrect(&rwf, 0.0,8.0, 0.0,-7.8);
- buildIndSize(&r, ((inst *)self)->myClass->classId, INDSIZE, INDSIZET);
- p->kids = makeValuatorf(p->kids, p, flags, &r, &inset, &rwf,
- NULL, &self->scale, INDSIZE, INDSIZET);
-
- /* individual's color control */
- /* flags = NULL;
- /* setrect(&r, 72,10, 192,50);
- /* initColorVals(p, flags, &r, self->descr->color);
- /* */
- /* death to fish control */
- flags = NULL;
- setrect(&r, 130,10, 50,100);
- setpt2d(&button, 1, 1);
- buildIndSnuff(&r, ((inst *)self)->myClass->classId, INDSNUFF,INDSNUFFT);
- p->kids = makeMenu(p->kids, p, flags, &r, &button,
- self, DIE, INDSNUFF, INDSNUFFT);
-
- /* individual's azimuth control */
- flags = NULL;
- setrect(&r, 72,10, 48,100);
- setpt2d(&inset, 0,15);
- setrect(&rw, 0,20, 0,-40);
- buildIndAzimuth(&r, ((inst *)self)->myClass->classId, INDAZ, INDAZT);
- p->kids = makeValMesg(p->kids, p, flags, &r, &inset, &rw, 0, 0,
- self, NEWAZIMUTH, NOAUTORESET, INDAZ, INDAZT);
-
- /* test menu buttons */
- /*
- flags = NULL;
- setrect(&r, 10, 160, 200, 200);
- setpt2d(&button, 4, 3);
- buildMenu1(&r, &button, MENU1, MENUH1);
- p->kids = makeMenu(p->kids, p, flags, &r, &button,
- self, TESTMENU, MENU1, MENUH1);
- /* */
- }
- #endif /* SPEEDER */
-
- /*
- * discard an obsolete Individual's control panel
- */
- removePanel(self)
- register individual *self;
- {
- self->controls = NULL;
- Msg(thePanel, INIT, NOARG, NULL);
- }
-
- burp(s,wanted)
- char *s;
- inst * wanted;
- {
- printf("hickup in %s\n", s);
- dumper = 1;
- dumpSubscribers("whole thing:", us->them.subscribers, wanted);
- dumper = 0;
- }
-